﻿using System;
using System.Collections.ObjectModel;
using System.Linq;

namespace HYGE.AsyncCommand
{
    /// <summary>
    /// 登録されたIAsyncCommandから発行されたIAsyncJobを収集し、ReadOnlyObservableCollection{IAsyncJob}として公開する。
    /// </summary>
    public class AsyncJobCollector
    {
        #region Fields

        #region collectedJobs
        /// <summary>
        /// 収集されたIAsyncJob。
        /// 公開用のReadOnlyObservableCollection{IAsyncJob}の元コレクション。
        /// </summary>
        private ObservableCollection<IAsyncJob> collectedJobs = null;
        #endregion

        #endregion

        #region Properties

        #region CollectedJobs
        /// <summary>
        /// 収集されたIAsyncJob。
        /// </summary>
        public ReadOnlyObservableCollection<IAsyncJob> CollectedJobs
        {
            get;
            private set;
        }
        #endregion

        #endregion

        #region Constructors

        #region Default
        /// <summary>
        /// デフォルトコンストラクタ。
        /// </summary>
        public AsyncJobCollector()
        {
            this.collectedJobs = new ObservableCollection<IAsyncJob>();
            this.CollectedJobs = new ReadOnlyObservableCollection<IAsyncJob>(this.collectedJobs);
        }
        #endregion

        #endregion

        #region EventHandlers

        #region AsyncCommand_JobCreated
        /// <summary>
        /// 登録されたIAsyncCommadのJobCreatedイベントハンドラ。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AsyncCommand_JobCreated(object sender, JobCreatedEventArgs e)
        {
            this.collectedJobs.Add(e.CreatedJob);
        }
        #endregion

        #endregion

        #region PublicMethods

        #region RegistCommand
        /// <summary>
        /// 指定されたIAsyncCommandを収集対象として登録する。
        /// </summary>
        /// <param name="asyncCommand"></param>
        public void RegistCommand(IAsyncCommand asyncCommand)
        {
            //引数チェック
            if (asyncCommand == null)
                throw (new ArgumentNullException("asyncCommand"));

            //登録
            asyncCommand.JobCreated += new EventHandler<JobCreatedEventArgs>(AsyncCommand_JobCreated);
        }
        #endregion

        #region UnregistCommand
        /// <summary>
        /// 指定されたIAsyncCommandの登録を解除する。
        /// </summary>
        /// <param name="asyncCommand"></param>
        public void UnregistCommand(IAsyncCommand asyncCommand)
        {
            //引数チェック
            if (asyncCommand == null)
                throw (new ArgumentNullException("asyncCommand"));

            //登録解除
            asyncCommand.JobCreated -= new EventHandler<JobCreatedEventArgs>(AsyncCommand_JobCreated);
        }
        #endregion

        #region ClearCompletedJobs
        /// <summary>
        /// 完了したIAsyncJobをCollectedJobsから削除する。
        /// </summary>
        public void ClearCompletedJobs()
        {
            var completedJobs = this.collectedJobs.Where(job => { return (job.IsCompleted); }).ToArray();
            foreach (IAsyncJob completedJob in completedJobs)
            {
                this.collectedJobs.Remove(completedJob);
                completedJob.Dispose();
            }
        }
        #endregion

        #region RemoveCompletedJob
        /// <summary>
        /// 指定された完了済のIAsyncJobをCollectedJobsから削除する。
        /// </summary>
        /// <param name="completedJob"></param>
        /// <returns></returns>
        public bool RemoveCompletedJob(IAsyncJob completedJob)
        {
            //引数確認
            if (completedJob == null)
                throw (new ArgumentNullException("completedJob"));
            if (!completedJob.IsCompleted)
                throw (new ArgumentException(Properties.Resources.AsyncJobCollector_RemoveCompletedJob_ArgumentExceptionMessage, "completedJob"));

            //値が存在しない場合はfalseを返却
            if (!this.collectedJobs.Contains(completedJob))
                return (false);

            this.collectedJobs.Remove(completedJob);
            completedJob.Dispose();
            return (true);
        }
        #endregion

        #endregion
    }
}
